﻿// <copyright file="ModFileComparer.cs" company="SingularityShift">
// Copyright (c) 2009 SingularityShift.com
// </copyright>
// <author>Ben McClure</author>
// <email>ben@singularityshift.com</email>
// <date>2009-08-14</date>
// <summary>Allows comparison of IMods by various file attributes</summary>
namespace GameLib.Games.Components
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// An indicator of what type of comparison to perform on a ModFile
    /// </summary>
    public enum ModFileComparisonType
    {
        /// <summary>
        /// Compare by the last modified timestamp on the file
        /// </summary>
        TimeModified,

        /// <summary>
        /// Compare by the File names (alphabetic)
        /// </summary>
        FileName
    }

    /// <summary>
    /// Compares two IMods by their file modification times
    /// </summary>
    /// <typeparam name="T">The type of IMod this comparer compares</typeparam>
    public class ModFileComparer<T> : IComparer<T> where T : IMod
    {
        /// <summary>
        /// Initializes a new instance of the ModFileComparer class.
        /// </summary>
        /// <param name="comparisonType">A ModFileComparisonType describing what to compare the mod files by</param>
        public ModFileComparer(ModFileComparisonType comparisonType)
        {
            this.ComparisonType = comparisonType;
            this.Reverse = false;
        }

        /// <summary>
        /// Initializes a new instance of the ModFileComparer class, specifying only whether or not the comparer should work in reverse
        /// </summary>
        /// <param name="comparisonType">A ModFileComparisonType describing what to compare the mod files by</param>
        /// <param name="reverse">A bool indicating if this comparison should happen in reverse or not</param>
        public ModFileComparer(ModFileComparisonType comparisonType, bool reverse)
        {
            this.ComparisonType = comparisonType;
            this.Reverse = reverse;
        }

        /// <summary>
        /// Initializes a new instance of the ModFileComparer class, specifying both a sort direction as well as a directory for the mods
        /// </summary>
        /// <param name="comparisonType">A ModFileComparisonType describing what to compare the mod files by</param>
        /// <param name="dir">The directory to look for the mods in</param>
        /// <param name="reverse">A bool indicating if this comparison should happen in reverse or not</param>
        public ModFileComparer(ModFileComparisonType comparisonType, string dir, bool reverse)
        {
            this.ComparisonType = comparisonType;
            this.Dir = dir;
            this.Reverse = reverse;
        }

        /// <summary>
        /// Gets or sets the type of comparison to perform
        /// </summary>
        public ModFileComparisonType ComparisonType
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether to compare in reverse
        /// </summary>
        public bool Reverse
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the directory the mods should be located in (otherwise whatever location is specified in each mod is used)
        /// </summary>
        public string Dir
        {
            get;
            set;
        }
        
        /// <summary>
        /// Compares two IMods by their last modification times
        /// </summary>
        /// <param name="x">The first IMod to compare</param>
        /// <param name="y">The second IMod to compare</param>
        /// <returns>An integer representing the order of the mods as defined by the comparison</returns>
        public int Compare(T x, T y)
        {
            string path1;
            string path2;
            if ((this.Dir.Length > 0) && Directory.Exists(this.Dir))
            {
                path1 = this.Dir + "\\" + Path.GetFileName(x.File);
                path2 = this.Dir + "\\" + Path.GetFileName(y.File);
            }
            else
            {
                path1 = x.File;
                path2 = y.File;
            }

            int result = 0;
            switch (this.ComparisonType)
            {
                case ModFileComparisonType.TimeModified:
                    DateTime modified1 = File.GetLastWriteTime(path1);
                    DateTime modified2 = File.GetLastWriteTime(path2);
                    result = modified1.CompareTo(modified2);
                    break;
                case ModFileComparisonType.FileName:
                    string fileName1 = Path.GetFileName(path1);
                    string fileName2 = Path.GetFileName(path2);
                    result = string.Compare(fileName1, fileName2, StringComparison.CurrentCultureIgnoreCase);
                    break;
            }
            
            return this.Reverse ? -result : result;
        }
    }
}
